home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / sockBuf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-27  |  13.5 KB  |  562 lines

  1. /* 
  2.  * sockBuf.c --
  3.  *
  4.  *    This file contains routines to manage the send and receive buffers
  5.  *    of a socket. The basic buffer operations are alloc, append, fetch, 
  6.  *    copy and remove. A buffer consists of a linked list of Sock_BufDataInfo
  7.  *    elements. Each element contains an area of memory with data. 
  8.  *
  9.  * Copyright 1987 Regents of the University of California
  10.  * All rights reserved.
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  */
  19.  
  20. #ifndef lint
  21. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/sockBuf.c,v 1.6 91/04/23 23:55:35 mottsmth Exp $ SPRITE (Berkeley)";
  22. #endif not lint
  23.  
  24.  
  25. #include "sprite.h"
  26. #include "ipServer.h"
  27. #include "stat.h"
  28. #include "socket.h"
  29. #include "sockInt.h"
  30.  
  31. #include "list.h"
  32.  
  33. /*
  34.  * CheckList is a debugging routine to make sure the 
  35.  */
  36. static void CheckList();
  37.  
  38.  
  39.  
  40. /*
  41.  *----------------------------------------------------------------------
  42.  *
  43.  * Sock_BufFetch --
  44.  *
  45.  *    Copies data from the front of a socket's receive buffer to a user's 
  46.  *    buffer. Depending on the flags, the data may or may not be 
  47.  *    removed from the buffer. The address of the sender of the data
  48.  *    is also available.
  49.  *
  50.  * Results:
  51.  *    SUCCESS        - the data was obtained from the buffer.
  52.  *    FS_WOULD_BLOCK    - there's no data in the buffer.
  53.  *
  54.  * Side effects:
  55.  *    Memory in a buffer element may be freed.
  56.  *
  57.  *----------------------------------------------------------------------
  58.  */
  59.  
  60. ReturnStatus
  61. Sock_BufFetch(sockPtr, flags, bufSize, buffer, amtCopiedPtr, addressPtr)
  62.     Sock_SharedInfo    *sockPtr;    /* Socket of interest. */
  63.     int            flags;        /* Type of operation: OR of
  64.                      * SOCK_BUF_STREAM, SOCK_BUF_PEEK. */
  65.     register int    bufSize;    /* How much data to get. */
  66.     Address        buffer;        /* Place to copy it to. */
  67.     int            *amtCopiedPtr;    /* Actual amount copied. */
  68.     Net_InetSocketAddr    *addressPtr;    /* Socket address of sender of the
  69.                      * data. */
  70. {
  71.     register Sock_BufInfo    *bufInfoPtr;
  72.     register Sock_BufDataInfo   *dataPtr;
  73.     register int        dataLen;
  74.     List_Links            *nextPtr;
  75.     int                amtCopied;
  76.  
  77.     bufInfoPtr = &sockPtr->recvBuf;
  78.  
  79.     *amtCopiedPtr = 0;
  80.  
  81.     if (bufSize == 0) {
  82.     return(SUCCESS);
  83.     }
  84.  
  85.     stats.sock.buffer.fetch++;
  86.  
  87.     /*
  88.      * Check if there's any data to return to the client.
  89.      */
  90.     if (List_IsEmpty(&bufInfoPtr->links)) {
  91.     if (Sock_IsRecvStopped(sockPtr)) {
  92.         return(SUCCESS);
  93.     } else {
  94.         return(FS_WOULD_BLOCK);
  95.     }
  96.     }
  97.  
  98.     amtCopied = 0;
  99.     if (flags & SOCK_BUF_STREAM) {
  100.  
  101.     /*
  102.      * Go through the list of buffers and copy the data to the
  103.      * output area. If the PEEK flag is not set, remove the
  104.      * buffer from the list.
  105.      */
  106.     (List_Links *) dataPtr = List_First(&bufInfoPtr->links);
  107.     while (!List_IsAtEnd(&bufInfoPtr->links, (List_Links *) dataPtr)) {
  108.  
  109.         dataLen = dataPtr->len;
  110.         if (dataLen <= bufSize) {
  111.  
  112.         bcopy(dataPtr->bufPtr, buffer, dataLen);
  113.         amtCopied    += dataLen;
  114.         buffer        += dataLen;
  115.         bufSize        -= dataLen;
  116.  
  117.         nextPtr = List_Next((List_Links *) dataPtr);
  118.         if (!(flags & SOCK_BUF_PEEK)) {
  119.             bufInfoPtr->size -= dataLen;
  120.             List_Remove((List_Links *) dataPtr);
  121.             free(dataPtr->base);
  122.             free((char *) dataPtr);
  123.         }
  124.         (List_Links *) dataPtr = nextPtr;
  125.  
  126.         if (bufSize == 0) {
  127.             break;
  128.         }
  129.         } else {
  130.         /*
  131.          * Take some of the data from this buffer. If the
  132.          * PEEK flag is not set, adjust the size and start
  133.          * to reflect the amount of data read.
  134.          */
  135.         bcopy(dataPtr->bufPtr, buffer, bufSize);
  136.         amtCopied    += bufSize;
  137.         if (!(flags & SOCK_BUF_PEEK)) {
  138.             bufInfoPtr->size    -= bufSize;
  139.             dataPtr->len    -= bufSize;
  140.             dataPtr->bufPtr    += bufSize;
  141.         }
  142.         break;
  143.         }
  144.     }
  145.     } else {
  146.  
  147.     /*
  148.      * Record-oriented read. 
  149.      */
  150.  
  151.     (List_Links *) dataPtr = List_First(&bufInfoPtr->links);
  152.  
  153.     /*
  154.      * If the client's buffer is too small, they won't get the whole
  155.      * packet.
  156.      */
  157.     if (bufSize < dataPtr->len) {
  158.         amtCopied = bufSize;
  159.     } else {
  160.         amtCopied = dataPtr->len;
  161.     }
  162.  
  163.     bcopy(dataPtr->bufPtr, buffer, amtCopied);
  164.  
  165.     /*
  166.      * Save the address of the sender in case the client wants to
  167.      * get it later.
  168.      */
  169.     if (addressPtr != (Net_InetSocketAddr *) NULL) {
  170.         *addressPtr = dataPtr->address;
  171.     }
  172.  
  173.     /*
  174.      * If the PEEK flag is not set, remove the packet from the list.
  175.      */
  176.     if (!(flags & SOCK_BUF_PEEK)) {
  177.         bufInfoPtr->size -= dataPtr->len;
  178.         List_Remove((List_Links *) dataPtr);
  179.         free(dataPtr->base);
  180.         free((char *) dataPtr);
  181.     }
  182.     }
  183.     *amtCopiedPtr = amtCopied;
  184.     CheckList(bufInfoPtr);
  185.     return(SUCCESS);
  186. }
  187.  
  188.  
  189. /*
  190.  *----------------------------------------------------------------------
  191.  *
  192.  * Sock_BufAppend --
  193.  *
  194.  *    Appends data to the end of a socket's send or receive buffer.
  195.  *
  196.  * Results:
  197.  *    SUCCESS        - all of the data were appended to the buffer.
  198.  *    FS_WOULD_BLOCK    - none or some of the data were appended.
  199.  *
  200.  * Side effects:
  201.  *    Memory for the list element is allocated.
  202.  *
  203.  *----------------------------------------------------------------------
  204.  */
  205.  
  206. ReturnStatus
  207. Sock_BufAppend(sockPtr, type, atomic, dataLen, data, base, addrPtr, 
  208.     amtAppendedPtr)
  209.     Sock_SharedInfo    *sockPtr;    /* Socket of interest. */
  210.     Sock_BufType    type;        /* Indicates RECV or SEND buffer. */
  211.     register int    dataLen;    /* Amount to append. */
  212.     Boolean        atomic;        /* If TRUE, don't append if can't fit
  213.                      * the whole packet. */
  214.     Address        data;        /* Buffer holding data. */
  215.     Address        base;        /* Base address of data. */
  216.     Net_InetSocketAddr    *addrPtr;    /* Sender of the data. */
  217.     int            *amtAppendedPtr; /* Actual amount of data appended to
  218.                       * the buffer. */
  219. {
  220.     register Sock_BufDataInfo    *dataPtr;
  221.     register Sock_BufInfo    *bufInfoPtr;
  222.     ReturnStatus        status;
  223.     int                freeSpace;
  224.  
  225.     if (type == SOCK_RECV_BUF) {
  226.     bufInfoPtr = &sockPtr->recvBuf;
  227.     } else {
  228.     bufInfoPtr = &sockPtr->sendBuf;
  229.     }
  230.  
  231.     stats.sock.buffer.append++;
  232.  
  233.     /*
  234.      * If there's not enough room in the buffer to hold all of the data,
  235.      * take as much as possible.  FS_WOULD_BLOCK is returned if we don't
  236.      * accept all the data so the Sprite kernel can make our client
  237.      * wait properly.
  238.      */
  239.  
  240.     freeSpace = bufInfoPtr->maxSize - bufInfoPtr->size;
  241.     if (dataLen > freeSpace) {
  242.     if ((freeSpace == 0) || atomic) {
  243.         if (amtAppendedPtr != (int *) NULL) {
  244.         *amtAppendedPtr = 0;
  245.         }
  246.         stats.sock.buffer.appendFail++;
  247.         return(FS_WOULD_BLOCK);
  248.     } else {
  249.         stats.sock.buffer.appendPartial++;
  250.         stats.sock.buffer.appPartBytes += dataLen;
  251.         dataLen = freeSpace;
  252.         status  = FS_WOULD_BLOCK;
  253.     }
  254.     } else {
  255.     status = SUCCESS;
  256.     }
  257.  
  258.     dataPtr = (Sock_BufDataInfo *) malloc(sizeof(Sock_BufDataInfo));
  259.     dataPtr->bufPtr    = data;
  260.     dataPtr->len    = dataLen;
  261.     dataPtr->base    = base;
  262.     if (addrPtr != (Net_InetSocketAddr *) NULL) {
  263.     dataPtr->address = *addrPtr;
  264.     }
  265.     List_InitElement((List_Links *) dataPtr);
  266.     List_Insert((List_Links *) dataPtr, LIST_ATREAR(&bufInfoPtr->links));
  267.  
  268.     bufInfoPtr->size += dataLen;
  269.     if (amtAppendedPtr != (int *) NULL) {
  270.     *amtAppendedPtr = dataLen;
  271.     }
  272.  
  273.     /*
  274.      * Make sure the list is not corrupted.
  275.      */
  276.     CheckList(bufInfoPtr);
  277.  
  278.     return(status);
  279. }
  280.  
  281.  
  282. /*
  283.  *----------------------------------------------------------------------
  284.  *
  285.  * Sock_BufRemove --
  286.  *
  287.  *    Removes a specific amount of data from the front of a buffer.
  288.  *    A special value for the amount removes all data from the buffer.
  289.  *
  290.  * Results:
  291.  *    None.
  292.  *
  293.  * Side effects:
  294.  *    Memory for the data and list elements is freed.
  295.  *
  296.  *----------------------------------------------------------------------
  297.  */
  298.  
  299. void
  300. Sock_BufRemove(sockPtr, type, amount)
  301.     Sock_SharedInfo    *sockPtr;    /* Socket of interest. */
  302.     Sock_BufType    type;        /* Indicates RECV or SEND buffer. */
  303.     register int    amount;        /* Amount to remove. -1 means all. */
  304. {
  305.     register Sock_BufDataInfo    *dataPtr;
  306.     register Sock_BufInfo    *bufInfoPtr;
  307.     List_Links            *nextPtr;
  308.  
  309.     if (type == SOCK_RECV_BUF) {
  310.     bufInfoPtr = &sockPtr->recvBuf;
  311.     } else {
  312.     bufInfoPtr = &sockPtr->sendBuf;
  313.     }
  314.  
  315.     stats.sock.buffer.remove++;
  316.  
  317.     /*
  318.      * An amount of -1 means to remove all data from the buffer.
  319.      */
  320.     if (amount == -1) {
  321.     amount = bufInfoPtr->size;
  322.     bufInfoPtr->size = 0;
  323.     } else if (amount < 0) {
  324.     panic("Sock_BufRemove: amount < 0 (%d)\n", amount);
  325.     return;
  326.     } else {
  327.     bufInfoPtr->size -= amount;
  328.     if (bufInfoPtr->size < 0) {
  329.         panic(
  330.         "Sock_BufRemove: tried to remove too much (%d)\n", amount);
  331.         return;
  332.     }
  333.     }
  334.  
  335.     dataPtr = (Sock_BufDataInfo *) List_First(&bufInfoPtr->links);
  336.     while (!List_IsAtEnd(&bufInfoPtr->links, (List_Links *) dataPtr)) {
  337.  
  338.     if (amount >= dataPtr->len) {
  339.         amount -= dataPtr->len;
  340.         nextPtr = List_Next((List_Links *) dataPtr);
  341.         List_Remove((List_Links *) dataPtr);
  342.         free(dataPtr->base);
  343.         free((char *) dataPtr);
  344.         if (amount == 0) {
  345.         break;
  346.         }
  347.         dataPtr = (Sock_BufDataInfo *) nextPtr;
  348.     } else {
  349.         /*
  350.          * The buffer is larger than the amount to be removed.
  351.          * Just adjust the size and start to reflect the amount removed.
  352.          */
  353.         dataPtr->len    -= amount;
  354.         dataPtr->bufPtr += amount;
  355.         amount = 0;
  356.         break;
  357.     }
  358.     }
  359.     if (amount > 0) {
  360.     panic("Sock_BufRemove: amount > 0 (%d)\n", amount);
  361.     }
  362.     CheckList(bufInfoPtr);
  363. }
  364.  
  365.  
  366. /*
  367.  *----------------------------------------------------------------------
  368.  *
  369.  * Sock_BufCopy --
  370.  *
  371.  *    Copies data from a socket buffer starting from a given offset to
  372.  *    user's buffer.
  373.  *
  374.  * Results:
  375.  *    None.
  376.  *
  377.  * Side effects:
  378.  *    None.
  379.  *
  380.  *----------------------------------------------------------------------
  381.  */
  382.  
  383. void
  384. Sock_BufCopy(sockPtr, type, offset, bufSize, buffer)
  385.     Sock_SharedInfo    *sockPtr;    /* Socket of interest. */
  386.     Sock_BufType    type;        /* Indicates RECV or SEND buffer. */
  387.     register int    offset;        /* Offset from beginning of buffer
  388.                      * to start copying. */
  389.     int            bufSize;    /* How much to copy. */
  390.     Address        buffer;        /* Buffer to hold the data. */
  391. {
  392.     register Sock_BufDataInfo    *dataPtr;
  393.     register Sock_BufInfo    *bufInfoPtr;
  394.     register int        dataLen;
  395.     Address            data;
  396.  
  397.     if (offset < 0) {
  398.     panic("Sock_BufCopy: negative offset: %d\n", offset);
  399.     return;
  400.     }
  401.  
  402.     stats.sock.buffer.copy++;
  403.  
  404.     if (type == SOCK_RECV_BUF) {
  405.     bufInfoPtr = &sockPtr->recvBuf;
  406.     } else {
  407.     bufInfoPtr = &sockPtr->sendBuf;
  408.     }
  409.  
  410.     LIST_FORALL(&bufInfoPtr->links, (List_Links *) dataPtr) {
  411.     data    = dataPtr->bufPtr;
  412.     dataLen = dataPtr->len;
  413.  
  414.     if (offset > 0) {
  415.         if (offset >= dataLen) {
  416.         /*
  417.          * The data segment ends before the offset.
  418.          */
  419.         offset -= dataLen;
  420.         continue;
  421.         } else {
  422.         /*
  423.          * We want to start copying inside this data segment. 
  424.          */
  425.         data     += offset;
  426.         dataLen    -= offset;
  427.         offset = 0;
  428.         }
  429.     } 
  430.     if (dataLen > bufSize) {
  431.         dataLen = bufSize;
  432.     } 
  433.     stats.sock.buffer.copyBytes += dataLen;
  434.     bcopy(data, buffer, dataLen );
  435.     buffer    += dataLen;
  436.     bufSize    -= dataLen;
  437.     if (bufSize == 0) {
  438.         break;
  439.     }
  440.     }
  441.     CheckList(bufInfoPtr);
  442. }
  443.  
  444.  
  445. /*
  446.  *----------------------------------------------------------------------
  447.  *
  448.  * Sock_BufAlloc --
  449.  *
  450.  *    Sets the maximum number of bytes that a buffer can hold
  451.  *    initializes the data list. 
  452.  *
  453.  * Results:
  454.  *    None.
  455.  *
  456.  * Side effects:
  457.  *    The data list is initialized.
  458.  *
  459.  *----------------------------------------------------------------------
  460.  */
  461.  
  462. void
  463. Sock_BufAlloc(sockPtr, type, maxSize)
  464.     Sock_SharedInfo    *sockPtr;    /* Socket of interest. */
  465.     Sock_BufType    type;        /* Indicates RECV or SEND buffer. */
  466.     int            maxSize;    /* Maximum # of bytes allowed. */
  467. {
  468.     if (type == SOCK_RECV_BUF) {
  469.     sockPtr->recvBuf.maxSize = maxSize;
  470.     List_Init(&sockPtr->recvBuf.links);
  471.     } else {
  472.     sockPtr->sendBuf.maxSize = maxSize;
  473.     List_Init(&sockPtr->sendBuf.links);
  474.     }
  475. }
  476.  
  477. /*
  478.  *----------------------------------------------------------------------
  479.  *
  480.  * Sock_BufSize --
  481.  *
  482.  *    Returns the the values of the various size parameters of a buffer.
  483.  *
  484.  * Results:
  485.  *    The size value.
  486.  *
  487.  * Side effects:
  488.  *    None.
  489.  *
  490.  *----------------------------------------------------------------------
  491.  */
  492.  
  493. int
  494. Sock_BufSize(sockPtr, type, request)
  495.     Sock_SharedInfo    *sockPtr;    /* Socket of interest. */
  496.     Sock_BufType    type;        /* Indicates RECV or SEND buffer. */
  497.     Sock_BufRequest    request;    /* Type of value wanted. */
  498. {
  499.     register Sock_BufInfo    *bufInfoPtr;
  500.     int size = 0;
  501.  
  502.     if (type == SOCK_RECV_BUF) {
  503.     bufInfoPtr = &sockPtr->recvBuf;
  504.     } else {
  505.     bufInfoPtr = &sockPtr->sendBuf;
  506.     }
  507.  
  508.     switch (request) {
  509.     case SOCK_BUF_USED:
  510.         size = bufInfoPtr->size;
  511.         break;
  512.  
  513.     case SOCK_BUF_FREE:
  514.         size = bufInfoPtr->maxSize - bufInfoPtr->size;
  515.         break;
  516.  
  517.     case SOCK_BUF_MAX_SIZE:
  518.         size = bufInfoPtr->maxSize;
  519.         break;
  520.  
  521.     default:
  522.         panic("Sock_BufSize: unknown request %d\n", request);
  523.         break;
  524.     }
  525.     return(size);
  526. }
  527.  
  528.  
  529. /*
  530.  *----------------------------------------------------------------------
  531.  *
  532.  * CheckList --
  533.  *
  534.  *    A debugging routine to make sure the buffer size agrees with
  535.  *    the sum of the data lengths in the buffer's queue.
  536.  *
  537.  * Results:
  538.  *    None.
  539.  *
  540.  * Side effects:
  541.  *    None.
  542.  *
  543.  *----------------------------------------------------------------------
  544.  */
  545.  
  546. static void
  547. CheckList(bufInfoPtr)
  548.     register Sock_BufInfo    *bufInfoPtr;
  549. {
  550.     register Sock_BufDataInfo    *dataPtr;
  551.     register int size = 0;
  552.  
  553.     LIST_FORALL(&bufInfoPtr->links, (List_Links *) dataPtr) {
  554.     size += dataPtr->len;
  555.     }
  556.  
  557.     if (size != bufInfoPtr->size) {
  558.     (void) panic("CheckList: size mismatch: sum = %d, list = %d\n",
  559.         size, bufInfoPtr->size);
  560.     }
  561. }
  562.